﻿// ========================================================================================
// Information: provide by Herbrandson
// Source: http://www.codeproject.com/KB/database/DynamicMethod_ILGenerator.aspx
// ========================================================================================
using System;
using System.Data;
using System.Reflection;
using System.Reflection.Emit;
namespace Super.Common.Mapping
{
    /// <summary>
    ///实体生成器
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class DynamicBuilder<T>
    {
        private static readonly MethodInfo getValueMethod = typeof(IDataRecord).GetMethod("get_Item", new Type[] { typeof(int) });

        private static readonly MethodInfo isDBNullMethod = typeof(IDataRecord).GetMethod("IsDBNull", new Type[] { typeof(int) });

        private delegate T Load(IDataRecord dataRecord);

        private Load handler;//最终执行动态方法的一个委托 参数是IDataRecord接口

        private DynamicBuilder() { }//私有构造函数

        public T Build(IDataRecord dataRecord)
        {
            return handler(dataRecord);//执行CreateBuilder里创建的DynamicCreate动态方法的委托
        }

        public static DynamicBuilder<T> CreateBuilder(IDataRecord dataRecord)
        {
            var dynamicBuilder = new DynamicBuilder<T>();

            //定义一个名为DynamicCreate的动态方法，返回值typof(T)，参数typeof(IDataRecord)
            var method = new DynamicMethod("DynamicCreate", typeof(T), new Type[] { typeof(IDataRecord) }, typeof(T), true);

            var generator = method.GetILGenerator();//创建一个MSIL生成器，为动态方法生成代码

            var result = generator.DeclareLocal(typeof(T));//声明指定类型的局部变量 可以T t;这么理解

            //The next piece of code instantiates the requested type of object and stores it in the local variable. 可以t=new T();这么理解
            generator.Emit(OpCodes.Newobj, typeof(T).GetConstructor(Type.EmptyTypes));
            generator.Emit(OpCodes.Stloc, result);

            for (int i = 0; i < dataRecord.FieldCount; i++)//数据集合，熟悉的for循环 要干什么你懂的 
            {
                PropertyInfo propertyInfo = typeof(T).GetProperty(dataRecord.GetName(i));//根据列名取属性  原则上属性和列是一一对应的关系
                Label endIfLabel = generator.DefineLabel();

                if (propertyInfo != null && propertyInfo.GetSetMethod() != null)//实体存在该属性 且该属性有SetMethod方法
                {
                    /*The code then loops through the fields in the data reader, finding matching properties on the type passed in. 
                     * When a match is found, the code checks to see if the value from the data reader is null.
                     */
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, isDBNullMethod);//就知道这里要调用IsDBNull方法 如果IsDBNull==true contine
                    generator.Emit(OpCodes.Brtrue, endIfLabel);

                    /*If the value in the data reader is not null, the code sets the value on the object.*/
                    generator.Emit(OpCodes.Ldloc, result);
                    generator.Emit(OpCodes.Ldarg_0);
                    generator.Emit(OpCodes.Ldc_I4, i);
                    generator.Emit(OpCodes.Callvirt, getValueMethod);//调用get_Item方法
                    generator.Emit(OpCodes.Unbox_Any, dataRecord.GetFieldType(i));
                    generator.Emit(OpCodes.Callvirt, propertyInfo.GetSetMethod());//给该属性设置对应值
                   
                    generator.MarkLabel(endIfLabel);
                }
            }

            /*The last part of the code returns the value of the local variable*/
            generator.Emit(OpCodes.Ldloc, result);
            generator.Emit(OpCodes.Ret);//方法结束，返回

            //完成动态方法的创建，并且创建执行该动态方法的委托，赋值到全局变量handler,handler在Build方法里Invoke
            dynamicBuilder.handler = (Load)method.CreateDelegate(typeof(Load));
            return dynamicBuilder;
        }
    }
}
